agentmux_srv\backend\storage\filestore/
ijson.rs1#![allow(dead_code)]
2use super::core::FileStore;
9use super::types::FileMeta;
10use crate::backend::storage::error::StoreError;
11
12impl FileStore {
13 const IJSON_NUM_COMMANDS: &'static str = "ijson:numcmds";
15 const IJSON_INC_BYTES: &'static str = "ijson:incbytes";
17
18 const IJSON_HIGH_COMMANDS: i64 = 100;
20 const IJSON_HIGH_RATIO: f64 = 3.0;
22 const IJSON_LOW_COMMANDS: i64 = 10;
24 const IJSON_LOW_RATIO: f64 = 1.0;
26
27 pub fn append_ijson(
29 &self,
30 zone_id: &str,
31 name: &str,
32 command: &serde_json::Value,
33 ) -> Result<(), StoreError> {
34 let file = self.stat(zone_id, name)?.ok_or(StoreError::NotFound)?;
35 if !file.opts.ijson {
36 return Err(StoreError::Other("file is not ijson".to_string()));
37 }
38
39 let cmd_bytes = serde_json::to_string(command)?;
40 let data = format!("{}\n", cmd_bytes);
41 self.append_data(zone_id, name, data.as_bytes())?;
42
43 let file = self.stat(zone_id, name)?.ok_or(StoreError::NotFound)?;
45 let mut meta = file.meta.clone();
46
47 let num_cmds = meta
48 .get(Self::IJSON_NUM_COMMANDS)
49 .and_then(|v| v.as_i64())
50 .unwrap_or(0)
51 + 1;
52 let inc_bytes = meta
53 .get(Self::IJSON_INC_BYTES)
54 .and_then(|v| v.as_i64())
55 .unwrap_or(0)
56 + data.len() as i64;
57
58 meta.insert(
59 Self::IJSON_NUM_COMMANDS.to_string(),
60 serde_json::json!(num_cmds),
61 );
62 meta.insert(
63 Self::IJSON_INC_BYTES.to_string(),
64 serde_json::json!(inc_bytes),
65 );
66 self.write_meta(zone_id, name, meta, false)?;
67
68 let file_size = file.size.max(1); let ratio = inc_bytes as f64 / file_size as f64;
71
72 let should_compact = num_cmds > Self::IJSON_HIGH_COMMANDS
73 || ratio >= Self::IJSON_HIGH_RATIO
74 || (num_cmds > Self::IJSON_LOW_COMMANDS && ratio >= Self::IJSON_LOW_RATIO);
75
76 if should_compact {
77 let _ = self.compact_ijson(zone_id, name);
78 }
79
80 Ok(())
81 }
82
83 pub fn compact_ijson(
86 &self,
87 zone_id: &str,
88 name: &str,
89 ) -> Result<(), StoreError> {
90 let data = self
92 .read_file(zone_id, name)?
93 .ok_or(StoreError::NotFound)?;
94
95 let content = String::from_utf8(data)
96 .map_err(|e| StoreError::Other(format!("invalid utf-8 in ijson file: {}", e)))?;
97
98 let compacted = crate::backend::ijson::compact_ijson(&content)
100 .map_err(|e| StoreError::Other(format!("ijson compact error: {}", e)))?;
101
102 let compacted_with_newline = format!("{}\n", compacted);
105 self.write_file(zone_id, name, compacted_with_newline.as_bytes())?;
106
107 let mut meta = FileMeta::new();
109 meta.insert(
110 Self::IJSON_NUM_COMMANDS.to_string(),
111 serde_json::json!(0),
112 );
113 meta.insert(
114 Self::IJSON_INC_BYTES.to_string(),
115 serde_json::json!(0),
116 );
117 self.write_meta(zone_id, name, meta, true)?;
118
119 Ok(())
120 }
121}